# module name node.py
# $Id: node.py 0c81aa997100 2012/09/03 07:53:27 pgurumur $
# Copyright (c) 2012 Prabhu Gurumurthy <pgurumur@gmail.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

__version__  = "$Revision: 0c81aa997100 $"
__author__   = "$Author: pgurumur $"
__modified__ = "$Date: 2012-09-03 07:53:27Z $"

try:
   import exception
   import stdlib
except ImportError:
   from . import exception
   from . import stdlib

def create(Value, Name, Type):
   retval = None
   if issubclass(float, Type):
      retval = NodeFloat(Value)
   elif issubclass(int, Type):
      retval = NodeInteger(Value)
   elif issubclass(str, Type):
      retval = NodeString(Value)

   if retval:
      retval.name = Name

   return retval

class Node(object):
   def __init__(self, Value = None, NodeType = None):
      self._name = None
      self._value = None
      if Value is None:
         raise exception.NodeError("no value defined for the node")

      if NodeType is None:
         raise exception.NodeError("no node type defined for the node")
      else:
         self._nodetype = NodeType

   def __str__(self):
      return str(self._name)

   def _check(self, Value):
      retval = False
      if Value and isinstance(Value, self._nodetype):
         retval = True

      return retval

   def SetName(self, Name = None):
      if Name:
         self._name = str(Name)

   def GetName(self):
      return self._name

   def SetValue(self, Value):
      self._value = Value

   def GetValue(self):
      return self._value

   name = property(GetName, SetName)
   value = property(GetValue, SetValue)

class NodeString(Node):
   def __init__(self, Value = None):
      super(NodeString, self).__init__(Value, str)
      self._value = str(Value)

   def __eq__(self, Other):
      retval = False
      if self._check(Other) and str(self._value) == Other:
         retval = True

      return retval

   def __hash__(self):
      return hash(self.value)

   def __add__(self, Other):
      if self._check(Other):
         self._value += str(Other)

      return self

   def __getitem__(self, Key):
      retval = ""
      if isinstance(Key, int):
         try:
            retval = self.value[Key]
         except IndexError as err:
            raise exception.NodeError("out of range")
      elif isinstance(Key, slice):
         for ix in range(Key.start, Key.stop):
            retval += self.value[ix]

      return NodeString(retval)

   def __len__(self):
      return len(self.value)

class NodeFloat(Node):
   def __init__(self, Value = None):
      super(NodeFloat, self).__init__(Value, float)
      try:
         self._value = float(Value)
      except ValueError as err:
         raise exception.NodeError(err)

   def __hash__(self):
      return hash(self._value)

   def __float__(self):
      return self._value

   def __lt__(self, Other):
      retval = False
      if self._check(Other) and float(self) < Other:
         retval = True

      return retval

   def __gt__(self, Other):
      retval = False
      if self._check(Other) and float(self) > Other:
         retval = True

      return retval

   def __eq__(self, Other):
      retval = False
      if self._check(Other) and float(self) == Other:
         retval = True

      return retval

   def __ne__(self, Other):
      retval = False
      if self._check(Other) and float(self) != Other:
         retval = True

      return retval

   def __le__(self, Other):
      retval = False
      if self._check(Other) and float(self) <= Other:
         retval = True

      return retval

   def __ge__(self, Other):
      retval = False
      if self._check(Other) and float(self) >= Other:
         retval = True

      return retval

   def __add__(self, Other):
      if self._check(Other) or isinstance(Other, int):
         self._value += float(Other)

      return float(self)

   def __sub__(self, Other):
      if self._check(Other) or isinstance(Other, int):
         self._value -= float(Other)

      return float(self)

   def __mul__(self, Other):
      if self._check(Other) or isinstance(Other, int):
         self._value *= float(Other)

      return float(self)

class NodeInteger(Node):
   def __init__(self, Value = None):
      super(NodeInteger, self).__init__(Value, int)
      try:
         self._value = int(Value)
      except ValueError as err:
         raise exception.NodeError(err)

   def __int__(self):
      return self._value

   def __hash__(self):
      return hash(self._value)

   def __lt__(self, Other):
      retval = False
      if self._check(Other) and int(self) < Other:
         retval = True

      return retval

   def __gt__(self, Other):
      retval = False
      if self._check(Other) and int(self) > Other:
         retval = True

      return retval

   def __eq__(self, Other):
      retval = False
      if self._check(Other) and int(self) == Other:
         retval = True

      return retval

   def __ne__(self, Other):
      retval = False
      if self._check(Other) and int(self) != Other:
         retval = True

      return retval

   def __le__(self, Other):
      retval = False
      if self._check(Other) and int(self) <= Other:
         retval = True

      return retval

   def __ge__(self, Other):
      retval = False
      if self._check(Other) and int(self) >= Other:
         retval = True

      return retval

   def __add__(self, Other):
      if self._check(Other):
         self._value += Other

      return int(self)

   def __sub__(self, Other):
      if self._check(Other):
         self._value -= Other

      return int(self)

   def __mul__(self, Other):
      if self._check(Other):
         self._value *= Other

      return int(self)

   def __and__(self, Other):
      if self._check(Other):
         self._value &= Other

      return int(self)

   def __or__(self, Other):
      if self._check(Other):
         self._value |= Other

      return int(self)

   def __xor__(self, Other):
      if self._check(Other):
         self._value ^= Other

      return int(self)
